﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Web.Configuration;

using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Search.Administration;

using Kiiro.Common.Entities;
using Kiiro.Common.Utility;
using Kiiro.Logging;
using Kiiro.Model.Utility;
using Kiiro.ExceptionManagement;

using AppName = Kiiro.Common.Utility.Constants.AppName;
using Permissions = Kiiro.Common.Utility.Constants.Permissions;
using SPSiteDefinition = Kiiro.Common.Utility.Constants.SPSiteDefinition;
using SecurityConstants = Kiiro.Common.Utility.Constants.Security;
using NavFields = Kiiro.Common.Utility.Constants.NavigationFieldNames;

namespace Kiiro.Model.EventHandlers
{
    public class KiiroPortal : SPFeatureReceiver
    {
        private const string SPGroupDescription = Constants.SPSiteDefinition.SPGroupDescription;

        public override void FeatureActivated ( SPFeatureReceiverProperties properties )
        {
            LoggingManager.LogMessage ( "TRACE", "Kiiro.Portal FeatureActivated Begin" );

            try
            {
                SPWeb web = properties.Feature.Parent as SPWeb;

                Guid siteCollectionId = web.Site.ID;
                string serverRelativeUrl = web.ServerRelativeUrl;

                web.AllowUnsafeUpdates = true;
                //needed when changing the default page
                if (web.GetFile("default.aspx").Exists)
                    web.Files["default.aspx"].Delete();

                //needed when remove the all activities page
                if (web.GetFile("AllActivity.aspx").Exists)
                    web.Files["AllActivity.aspx"].Delete();

                KiiroSolutionControllerHelpers.EnsureSiteEvents ( siteCollectionId );
                KiiroSolutionControllerHelpers.EnsureSiteFeatures ( siteCollectionId, serverRelativeUrl );
                KiiroSolutionControllerHelpers.EnsureWebEvents ( siteCollectionId, serverRelativeUrl );
                KiiroSolutionControllerHelpers.EnsureWebFeaturesPortal ( siteCollectionId, serverRelativeUrl );

                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Activity History" ) == 0 )
                    web.Lists.Add ( "Activity History", "Kiiro Activity History List", "Lists/ActivityHistory", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50000, "" );
                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Users" ) == 0 )
                    web.Lists.Add ( "Users", "Kiiro User List", "Lists/Users", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50003, "" );
                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Projects" ) == 0 )
                    web.Lists.Add ( "Projects", "Kiiro Projects List", "Lists/Projects", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50004, "" );
                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Setup" ) == 0 )
                    web.Lists.Add ( "Setup", "Kiiro Setup List", "Lists/Setup", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50005, "" );
                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Kiiro Main Navigation" ) == 0 )
                    web.Lists.Add ( "Kiiro Main Navigation", "Kiiro Main Navigation List", "Lists/MainNavigation", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50100, "" );
                if ( web.Lists.Cast<SPList> ( ).Count ( list => list.Title == "Kiiro Sub Navigation" ) == 0 )
                    web.Lists.Add ( "Kiiro Sub Navigation", "Kiiro Sub Navigation List", "Lists/SubNavigation", "2506CDB8-FB9D-4d96-A81E-5BEC418EE1C7", 50101, "" );
                
                // Lists must be created before calling EnsureListEventHandlers and EnsureTimerJobs 
                KiiroSolutionControllerHelpers.EnsureListEventHandlers ( siteCollectionId, serverRelativeUrl );
                KiiroSolutionControllerHelpers.EnsureTimerJobs ( siteCollectionId );

                if ( string.IsNullOrEmpty ( web.Properties [ "IsProvisioned" ] ) )
                {
                    LoggingManager.LogMessage ( "TRACE", "Provisioning Portal Groups Begin" );
                    SetupSiteGroupsAndUsers ( web );
                    LoggingManager.LogMessage ( "TRACE", "Provisioning Portal Groups End" );

                    web.Properties [ "IsProvisioned" ] = bool.TrueString;
                    web.Properties.Update ( );
                }

                if ( string.IsNullOrEmpty ( web.Properties [ "IsNavigationProvisioned" ] ) )
                {
                    KiiroSolutionControllerHelpers.EnsureNavigationLists ( siteCollectionId, serverRelativeUrl );
                }

                web.AllowAutomaticASPXPageIndexing = true;
                web.ASPXPageIndexMode = WebASPXPageIndexMode.Always;
                web.NoCrawl = false;
                web.PresenceEnabled = false;
                web.QuickLaunchEnabled = false;
                web.Update ( );

                LicensingModel.InvalidateActiveUsersCount ( siteCollectionId, serverRelativeUrl );
                LicensingModel.InvalidateOpenProjectsCount ( siteCollectionId, serverRelativeUrl );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }

            LoggingManager.LogMessage ( "TRACE", "Kiiro.Portal FeatureActivated End" );
        }


        private void CreateNavInstanceData ( SPWeb web, string listUrl, List<NavigationItem> navItems )
        {
            try
            {
                SPList list = web.GetList ( listUrl);

                foreach ( NavigationItem navItem in navItems )
                {
                    SPListItem listItem = list.Items.Add ( );

                    foreach ( string display in navItem.PageDisplayCollection )
                        listItem [ NavFields.PageDisplayCollection ] += display + "\r\n";

                    foreach ( string hilite in navItem.PageHiLiteCollection )
                        listItem [ NavFields.PageHiLiteCollection ] += hilite + "\r\n";

                    listItem [ NavFields.GroupVisibility ] = FormattingHelpers.ListOfKiiroGroupsToFieldText ( navItem.GroupVisibility );

                    listItem [ NavFields.IsVisible ] = navItem.IsVisible;
                    listItem [ NavFields.Sequence ] = navItem.Sequence;
                    listItem [ NavFields.SiteLevel ] = navItem.SiteLevel;
                    listItem [ NavFields.TargetUrl ] = navItem.TargetUrl;
                    listItem [ NavFields.Title ] = navItem.Title;

                    listItem.SystemUpdate ( );
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private void SetupSiteGroupsAndUsers ( SPWeb web )
        {
            try
            {
                if ( web.HasUniqueRoleAssignments )
                {
                    if ( !web.IsRootWeb )
                    {
                        web.BreakRoleInheritance ( true );
                        web.RoleDefinitions.BreakInheritance ( true, true );
                    }

                    SetupOwnersGroup ( web );
                    SetupMembersGroup ( web );
                    SetupVisitorsGroup ( web );
                }

                SetupUsers ( web );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private void SetupOwnersGroup ( SPWeb web )
        {
            try
            {
                string name = string.Format ( "{0} Owners - {1}", AppName.Proper, web.Title );
                int count = web.SiteGroups.Cast<SPGroup> ( ).Count ( x => x.Name.Contains ( name ) );
                name = count > 0 ? string.Format ( "{0}({1})", name, count ) : name;

                web.SiteGroups.Add ( name, web.Author, web.Author, string.Format ( SPGroupDescription, "Full Control", web.Title ) );
                SPGroup owners = web.SiteGroups [ name ];
                owners.Owner = web.IsRootWeb ? owners : web.ParentWeb.AssociatedOwnerGroup;
                owners.Update ( );

                web.AssociatedOwnerGroup = owners;

                SPRoleDefinition fullControl = web.RoleDefinitions.Cast<SPRoleDefinition> ( )
                    .Where ( role => role.Name == "Full Control" )
                    .First ( );

                SPRoleAssignment roleAssignment = new SPRoleAssignment ( owners as SPPrincipal );
                roleAssignment.RoleDefinitionBindings.Add ( fullControl );
                web.RoleAssignments.Add ( roleAssignment );

                web.Update ( );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private void SetupMembersGroup ( SPWeb web )
        {
            try
            {
                string name = string.Format ( "{0} Members - {1}", AppName.Proper, web.Title );
                int count = web.SiteGroups.Cast<SPGroup> ( ).Count ( x => x.Name.Contains ( name ) );
                name = count > 0 ? string.Format ( "{0}({1})", name, count ) : name;

                web.SiteGroups.Add ( name, web.Author, web.Author, string.Format ( SPGroupDescription, "Contribute", web.Title ) );
                SPGroup members = web.SiteGroups [ name ];
                members.Owner = web.IsRootWeb ? web.AssociatedOwnerGroup : web.ParentWeb.AssociatedMemberGroup;
                members.Update ( );

                web.AssociatedMemberGroup = members;

                SPRoleDefinition contribute = web.RoleDefinitions.Cast<SPRoleDefinition> ( )
                    .Where ( role => role.Name == "Contribute" )
                    .First ( );

                SPRoleAssignment roleAssignment = new SPRoleAssignment ( members as SPPrincipal );
                roleAssignment.RoleDefinitionBindings.Add ( contribute );
                web.RoleAssignments.Add ( roleAssignment );

                web.Update ( );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private void SetupVisitorsGroup ( SPWeb web )
        {
            try
            {
                string name = string.Format ( "{0} Visitors - {1}", AppName.Proper, web.Title );
                int count = web.SiteGroups.Cast<SPGroup> ( ).Count ( x => x.Name.Contains ( name ) );
                name = count > 0 ? string.Format ( "{0}({1})", name, count ) : name;

                web.SiteGroups.Add ( name, web.Author, web.Author, string.Format ( SPGroupDescription, "Read", web.Title ) );
                SPGroup visitors = web.SiteGroups [ name ];
                visitors.Owner = web.IsRootWeb ? web.AssociatedOwnerGroup : web.ParentWeb.AssociatedVisitorGroup;
                visitors.Update ( );

                web.AssociatedVisitorGroup = visitors;

                SPRoleDefinition read = web.RoleDefinitions.Cast<SPRoleDefinition> ( )
                    .Where ( role => role.Name == "Read" )
                    .First ( );

                SPRoleAssignment roleAssignment = new SPRoleAssignment ( visitors as SPPrincipal );
                roleAssignment.RoleDefinitionBindings.Add ( read );
                web.RoleAssignments.Add ( roleAssignment );

                web.Update ( );
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }
        

        private void SetupUsers ( SPWeb web )
        {
            try
            {
                using ( SPSite site = new SPSite ( web.Url ) )
                {
                    SPWebApplication webApplication = site.WebApplication;

                    SetupSearchUser ( site.ID, web.ServerRelativeUrl );

                    if ( webApplication.IisSettings
                        .Count ( x => ( ( SPIisSettings ) x.Value ).AuthenticationMode == AuthenticationMode.Windows ) > 0 )
                    {
                        SetupGuestUser ( site.ID, web.ServerRelativeUrl );
                        SetupADAdminUser ( site.ID, web.ServerRelativeUrl );
                    }

                    if ( webApplication.IisSettings
                        .Count ( x => ( ( SPIisSettings ) x.Value ).MembershipProvider == Permissions.FBAMembershipProviderName ) > 0 )
                    {
                        SetupFormsAdminUser ( site.ID, web.ServerRelativeUrl );
                    }
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private void SetupSearchUser ( Guid siteCollectionId, string serverRelativeUrl )
        {
            try
            {
                using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    SPSearchService searchService = SPFarm.Local.Services.GetValue<SPSearchService> ( "SPSearch" );
                    string login = ( ( SPWindowsService ) searchService ).ProcessIdentity.Username;
                    SPUser spUser = web.EnsureUser ( login );

                    User search = new User
                    {
                        FirstName = "Indexing",
                        LastName = "Account",
                        Login = login,
                        IsActive = true,
                        IsSharePointAccount = true,
                        CreatedDate = DateTime.Now,
                        ModifiedDate = DateTime.Now,
                        Title = "Required Account used for Search",
                        EditType = EditType.Created,
                        SPUserId = spUser.ID
                    };

                    UserModel.ProvisionerSave ( search, siteCollectionId, serverRelativeUrl );
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private void SetupGuestUser ( Guid siteCollectionId, string serverRelativeUrl )
        {
            try
            {
                using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    string login = SecurityConstants.AD_AUTH_USERS_DOMAIN_GROUP_NAME;
                    SPUser spUser = web.EnsureUser ( login );

                    User guest = new User
                    {
                        FirstName = "Guest",
                        Login = login,
                        IsActive = true,
                        IsSharePointAccount = true,
                        CreatedDate = DateTime.Now,
                        ModifiedDate = DateTime.Now,
                        Title = "Guest Account",
                        EditType = EditType.Created,
                        SPUserId = spUser.ID
                    };

                    UserModel.ProvisionerSave ( guest, siteCollectionId, serverRelativeUrl );

                    web.AssociatedMemberGroup.RemoveUser ( spUser );
                    web.AssociatedVisitorGroup.AddUser ( spUser );
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private void SetupADAdminUser ( Guid siteCollectionId, string serverRelativeUrl )
        {
            try
            {
                using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    string login = web.Author.LoginName;
                    User adUserInfo = UserModel.GetADUser ( login );

                    User adAdmin = new User
                    {
                        Login = login,
                        Email = adUserInfo.Email ?? "ad.admin@yourcompany.com",
                        FirstName = adUserInfo.FirstName ?? "Admin",
                        LastName = adUserInfo.LastName ?? "- AD",
                        IsActive = true,
                        IsAdministrator = true,
                        CreatedDate = DateTime.Now,
                        ModifiedDate = DateTime.Now,
                        Title = adUserInfo.Title ?? "Site Administrator - AD",
                        CompanyName = adUserInfo.CompanyName,
                        PhoneNumber = adUserInfo.PhoneNumber,
                        EditType = EditType.Created,
                        SPUserId = web.Author.ID
                    };

                    UserModel.ProvisionerSave ( adAdmin, siteCollectionId, serverRelativeUrl );
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }

        private void SetupFormsAdminUser ( Guid siteCollectionId, string serverRelativeUrl )
        {
            try
            {
                using ( SPWeb web = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
                {
                    string login = string.Format ( "{0}Admin", AppName.Lower );
                    string fullLogin = string.Format ( "{0}{1}", Permissions.FBAMembershipProviderNameColon, login );
                    int spUserId = default ( int );

                    using ( SPWeb systemWeb = SPHelpers.GetSystemWeb ( siteCollectionId, serverRelativeUrl ) )
                    {
                        systemWeb.SiteUsers.Add ( fullLogin, "forms.admin@yourcompany.com", "Admin - Forms", "" );
                        spUserId = systemWeb.EnsureUser ( fullLogin ).ID;
                    }

                    User formsAdmin = new User
                    {
                        Email = "forms.admin@yourcompany.com",
                        FirstName = "Admin",
                        LastName = "- Forms",
                        Login = login,
                        Password = UserModel.HashPassword ( AppName.Lower ),
                        IsActive = true,
                        IsAdministrator = true,
                        IsFormsUser = true,
                        CreatedDate = DateTime.Now,
                        ModifiedDate = DateTime.Now,
                        Title = "Site Administrator - Forms",
                        EditType = EditType.Created,
                        SPUserId = spUserId
                    };

                    UserModel.ProvisionerSave ( formsAdmin, siteCollectionId, serverRelativeUrl );
                }
            }
            catch ( Exception ex )
            {
                ExceptionManager.HandleException ( ex, false );
            }
        }


        public override void FeatureDeactivating ( SPFeatureReceiverProperties properties ) { }

        public override void FeatureInstalled ( SPFeatureReceiverProperties properties ) { }

        public override void FeatureUninstalling ( SPFeatureReceiverProperties properties ) { }
    }
}
/*************************************************************************
 * 
 * $Log: /Internal Projects/Kiiro/Kiiro.Model/EventHandlers/FeatureEventHandlers/KiiroPortal.cs $
 * 
 * 17    1/12/10 9:43a Camerons
 * 
 * 16    1/11/10 11:51a Camerons
 * 
 * 15    1/07/10 2:40p Camerons
 * 
 * 14    1/07/10 12:28p Camerons
 * 
 * 13    1/06/10 10:44p Camerons
 * 
 * 12    1/06/10 12:39p Camerons
 * 
 ************************************************************************/